#ifndef LMMPATHPOOL_HPP
#define LMMPATHPOOL_HPP

#include <vector>
#include "LMMAdvancer.hpp"
namespace TermStructure
{
    //! A class to generate a pool of paths from LMMAdvancer;
    /*!
     To Generate NumberOfPath paths for an index range. This pool is provide to reduce the number of LMMAdvancer's PreAdvance(), which is time consuming because of different decompositions.
     */
	template<typename TVarianceStructure,template<typename, typename,typename> class TMultiDimensionGaussian, typename T = double,typename TSize = long>
	class LMMPathPool
	{
		LMMAdvancer<TVarianceStructure,TMultiDimensionGaussian, T,TSize> *_advancer;
		mutable std::vector<std::vector<ForwardRateSequence<T,TSize> *> > _pool;
	public:
        void ReleasePool() const
        {
            for(TSize i = 0; i < NumberOfPath; i++)
            {
                for(TSize j = 1; j < _pool.size(); j++)
                {
                    delete _pool[i][j];
                }
                _pool.clear();
            }
        }
        //! Get all the paths at once.
		std::vector<std::vector<ForwardRateSequence<T,TSize> *> > const *GetPool() const
		{
			return &_pool;
		}
        //! Set the underlying LMMAdvancer.
		void SetLMMAdvancer(LMMAdvancer<TVarianceStructure,TMultiDimensionGaussian, T,TSize> &advancer)
		{
			this->_advancer = &advancer;
		}
        //! Number of Path need to be generated
		TSize NumberOfPath;
        //! Current Time Index, Where all the Forward Rates start
		TSize CurrentTimeIndex;
        //! End of the index, where the forward rates all ends.
		TSize EndIndex;
        //! Get the generated ForwardRateSequence for pathID and TimeIndex. Note the function doesn't require adjusting TimeIndex for currentTimeIndex
		ForwardRateSequence<T,TSize> &operator()(TSize pathID, TSize TimeIndex)
		{
			return *_pool[pathID][TimeIndex - CurrentTimeIndex];
		}
        //! Get the generated ForwardRAteSequence for path ID and timeIndex. Note the function doesn't require adjusting TimeIndex for currentTimeIndex
		const ForwardRateSequence<T,TSize> &operator()(TSize pathID, TSize TimeIndex) const
		{
			return *_pool[pathID][TimeIndex - CurrentTimeIndex];
		}
        //! Generate the path pool.
		void Generate() const
		{
			if(_pool.size() != 0) return;
			for(TSize i = 0; i < NumberOfPath; i++)
			{
				std::vector<ForwardRateSequence<T,TSize> *> aPath;
				aPath.push_back(&(this->_advancer->CurrentSequence()));
				this->_pool.push_back(aPath);
			}
			for(TSize k = CurrentTimeIndex+ 1; k<=EndIndex; k++) 
			{
				_advancer->CurrentTime = _advancer->GetTimeSequence().GetTime(k-1);
				_advancer->TimeStep = _advancer->GetTimeSequence().TimeDifference(k);
				_advancer->PreAdvance();
				for(TSize i = 0; i < NumberOfPath; i++)
				{
					_advancer->SetForwardRateSequence(*(_pool[i][k-CurrentTimeIndex-1]));
					_advancer->SingleAdvance();
					this->_pool[i].push_back(&(_advancer->NextSequence()));
				}
			}
		}
	};
}

#endif